#include "mainwindow.h"
#include "ui_mainwindow.h"



MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /* 安装事件过滤器 */
    ui->textEdit_json_file->installEventFilter(this);
    ui->textEdit_input->installEventFilter(this);
    ui->textEdit_output->installEventFilter(this);

    /* 设置窗口标题 */
    this->setWindowTitle("协议解析");

    init_protocol_list();       //导入协议
    if(ui->comboBox_protocol_type->count() > 0)
        ui->comboBox_protocol_type->activated(0);   //加载第一个协议

    //设置拖拽的下限,防止窗口因拖拽而被隐藏
    ui->splitter->setCollapsible(0,false);
    ui->splitter->setCollapsible(1,false);
    ui->splitter_2->setCollapsible(1,false);
    ui->splitter_2->setCollapsible(0,false);

    /* 本示例为垂直滚动条，因此滚动条会一直处于:vertical伪状态，所以对滚动条的每个子控件的设置都需要指定该状态 */
    ui->textEdit_json_file->verticalScrollBar()->setStyleSheet(
            "QScrollBar:vertical{"        //垂直滑块整体
            "background:#FFFFFF;"  //背景色
            "padding-top:20px;"    //上预留位置（放置向上箭头）
            "padding-bottom:20px;" //下预留位置（放置向下箭头）
            "padding-left:3px;"    //左预留位置（美观）
            "padding-right:3px;"   //右预留位置（美观）
            "border-left:1px solid #d7d7d7;}"//左分割线
            "QScrollBar::handle:vertical{"//滑块样式
            "background:#dbdbdb;"  //滑块颜色
            "border-radius:6px;"   //边角圆润
            "min-height:80px;}"    //滑块最小高度
            "QScrollBar::handle:vertical:hover{"//鼠标触及滑块样式
            "background:#d0d0d0;}" //滑块颜色
            "QScrollBar::add-line:vertical{"//向下箭头样式
            "background:url(:/images/resource/images/checkout/down.png) center no-repeat;}"
            "QScrollBar::sub-line:vertical{"//向上箭头样式
            "background:url(:/images/resource/images/checkout/up.png) center no-repeat;}");

}

MainWindow::~MainWindow()
{
    external_data_psrsing.clear();
    delete ui;
}


bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{

    if(watched==ui->textEdit_input || watched==ui->textEdit_output || watched==ui->textEdit_json_file)
    {
        QTextEdit *text_edit = static_cast<QTextEdit*>(watched);
        //CTRL+鼠标滚轮键
        QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
        if((event->type() == QEvent::Wheel) && (keyEvent->modifiers() == (Qt::ControlModifier)))
        {

            QWheelEvent *e = static_cast<QWheelEvent*>(event);
            if(e->delta()>0)
            {
                text_edit->zoomIn();
            }
            else {
                text_edit->zoomOut();
            }
        }
    }

    return false;
}


//初始化协议列表
void MainWindow::init_protocol_list()
{
    QFile file("application.json");
    if(!file.open(QIODevice::ReadOnly ))
    {
        /* 如果打开文件失败 可能是第一次运行 没有找到 那么就创建一个 */
        file.open(QIODevice::ReadWrite|QIODevice::Text);
        file.write("{\"applicaton_author\":\"mzy2364\",\"protocol_list\":[]}");
        application_file_data.clear();
        application_file_data = "{\"applicaton_author\":\"mzy2364\",\"protocol_list\":[]}";
    }
    else{
        application_file_data.clear();
        application_file_data = file.readAll();
    }



    QJsonParseError jsonError;
    QJsonDocument doucment = QJsonDocument::fromJson(application_file_data, &jsonError);  // 转化为 JSON 文档
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError))
    {  // 解析未发生错误
        if (doucment.isObject())
        { // JSON 文档为对象
            QJsonObject object = doucment.object();  // 转化为对象
            if(object.contains("protocol_list"))     //查找指定的key
            {
                QJsonValue value = object.value("protocol_list");

                if(value.isArray())
                {
                    QJsonArray data_array = value.toArray();

                    foreach(QJsonValue data_value,data_array)
                    {
                        QJsonObject data_object = data_value.toObject();
                        /* 获取数据 */
                        QJsonValue value_path = data_object.value("path");
                        /* 检查数据完整性 */
                        if(value_path.isNull())
                        {
                            continue;
                        }
                        /* 判断是不是真实文件 */
                        QFileInfo file_info(value_path.toString());
                        if(file_info.isFile())
                        {
                            /* 填充数据 */
                            protocol_file_path_list.append(value_path.toString());
                        }

                    }
                    goto json_success;
                }
            }
        }
        else {
            goto json_error;
        }
    }
    else {
        goto json_error;
    }

json_success:
    file.close();
    foreach(QString s,protocol_file_path_list)
    {
        QFileInfo file_info(s);
        ui->comboBox_protocol_type->addItem(file_info.fileName());
    }

    return;

json_error:
    QMessageBox::StandardButton btn = QMessageBox::Ok;
    btn = QMessageBox::warning(this,"error","初始化配置文件错误,是否重新创建",QMessageBox::Ok | QMessageBox::Cancel,QMessageBox::Cancel);
    if(btn == QMessageBox::Ok)
    {
        file.close();
        /* 清空文件内容 */
        file.open(QFile::WriteOnly|QFile::Truncate);
        file.close();
        /* 写入初始化信息 */
        file.open(QIODevice::ReadWrite|QIODevice::Text);
        file.write("{\"applicaton_author\":\"mzy2364\",\"protocol_list\":[]}");
        application_file_data.clear();
        application_file_data = "{\"applicaton_author\":\"mzy2364\",\"protocol_list\":[]}";
        file.close();
    }
}

void MainWindow::init_protocol_list(QByteArray file_data)
{
    if(file_data.isEmpty())
    {
        init_protocol_list();
        return;
    }
    QJsonParseError jsonError;
    QJsonDocument doucment = QJsonDocument::fromJson(file_data, &jsonError);  // 转化为 JSON 文档
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError))
    {  // 解析未发生错误
        if (doucment.isObject())
        { // JSON 文档为对象
            QJsonObject object = doucment.object();  // 转化为对象
            if(object.contains("protocol_list"))     //查找指定的key
            {
                QJsonValue value = object.value("protocol_list");

                if(value.isArray())
                {
                    QJsonArray data_array = value.toArray();

                    foreach(QJsonValue data_value,data_array)
                    {
                        QJsonObject data_object = data_value.toObject();
                        /* 获取数据 */
                        QJsonValue value_path = data_object.value("path");
                        /* 检查数据完整性 */
                        if(value_path.isNull())
                        {
                            continue;
                        }
                        /* 判断是不是真实文件 */
                        QFileInfo file_info(value_path.toString());
                        if(file_info.isFile())
                        {
                            /* 填充数据 */
                            protocol_file_path_list.append(value_path.toString());
                        }

                    }
                }
            }
        }
    }

    ui->comboBox_protocol_type->clear();
    foreach(QString s,protocol_file_path_list)
    {
        QFileInfo file_info(s);
        ui->comboBox_protocol_type->addItem(file_info.fileName());
    }
}


void MainWindow::on_pushButton_start_clicked()
{
    QString input_str = ui->textEdit_input->toPlainText();  //输入的字符串
    if(input_str.isEmpty())
    {
        input_data.clear();
        return;
    }
    ui->textEdit_output->clear();
    input_data = HexStringToByteArray(input_str);

    if(!external_data_psrsing.isEmpty())
    {
        ui->textEdit_output->append("CRC:"+check_crc_from_js(input_data.toHex(),ui->lineEdit_crc_func_name->text()));
        output_data = data_parsing(input_data,external_data_psrsing,ui->checkBox_disp_hex->isChecked());
    }
    foreach(QString s,output_data)
    {
        ui->textEdit_output->append(s);
    }
}


QByteArray MainWindow::HexStringToByteArray(QString HexString)
{
    bool ok;
    QByteArray ret;
    QStringList sl;
    HexString = HexString.trimmed();
    HexString = HexString.simplified();
    //为了适配有空格和没有空格的字符串,先删除所有空格,再进行分割
    HexString = HexString.remove(QRegExp("\\s"));
    QString temp_str;
    foreach(QString s,HexString)
    {
        temp_str.append(s);
        if(temp_str.length()>=2)
        {
            sl.append(temp_str);
            temp_str.clear();
        }

    }
    foreach (QString s, sl) {
        if(!s.isEmpty())
        {
            char c = static_cast<char>(s.toInt(&ok,16) & 0xFF);
            if(ok)
            {
                ret.append(c);
            }
            else
            {
                qDebug()<<"非法的16进制字符："<<s;
            }
        }
    }
    return ret;
}

//导入协议
void MainWindow::on_pushButton_import_protocol_clicked()
{
    QString path = "./";
    QString fileName = QFileDialog::getOpenFileName(this,("打开协议文件"),path,tr("json文件(*.json)"));
    if(fileName.isEmpty())
        return;
    ui->lineEdit_file_path->setText(fileName);

    if(import_protocol(fileName,external_data_psrsing)==false)
    {
        QMessageBox::warning(this,"error","协议文件异常",QMessageBox::Ok);
        return;
    }

    QJsonParseError jsonError;
    QJsonDocument doucment = QJsonDocument::fromJson(application_file_data, &jsonError);  // 转化为 JSON 文档
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError))
    {  // 解析未发生错误
        if (doucment.isObject())
        { // JSON 文档为对象
            QJsonObject object = doucment.object();  // 转化为对象
            if(object.contains("protocol_list"))     //查找指定的key
            {
                QJsonValue value = object.value("protocol_list");

                if(value.isArray())
                {
                    int index = 0;
                    QJsonArray data_array = value.toArray();
                    foreach(QJsonValue data_value,data_array)
                    {

                        QJsonObject data_object = data_value.toObject();
                        QJsonValue value_path = data_object.value("path");
                        if(value_path.toString() == fileName) //如果找到相同的文件路径
                        {
                            if(ui->comboBox_protocol_type->count()>index)
                            {
                                ui->comboBox_protocol_type->setCurrentIndex(index);
                                ui->comboBox_protocol_type->activated(index);
                            }
                            return;
                        }
                        index++;
                    }

                    QJsonObject protocol_list_object_new;
                    protocol_list_object_new.insert("path",fileName);
                    data_array.append(protocol_list_object_new);
                    object.remove("protocol_list");     //删除key
                    object.insert("protocol_list",data_array);  //重新添加key
                    doucment.setObject(object);
                    //保存文件
                    application_file_data.clear();
                    application_file_data = doucment.toJson();
                    QFile file("application.json");
                    if(file.open(QIODevice::ReadWrite|QIODevice::Text))
                    {
                        file.write(application_file_data);
                        file.close();
                    }
                    protocol_file_path_list.clear();
                    init_protocol_list(application_file_data);
                    if(ui->comboBox_protocol_type->count() > 0)
                    {
                        ui->comboBox_protocol_type->setCurrentIndex(ui->comboBox_protocol_type->count()-1);
                        ui->comboBox_protocol_type->activated(ui->comboBox_protocol_type->count()-1);
                        //qDebug()<<"选择最后一行";
                    }
                }
            }
        }
    }

}

void MainWindow::on_pushButton_clear_clicked()
{
    external_data_psrsing.clear();
    ui->lineEdit_file_path->clear();
    ui->textEdit_json_file->clear();
}

QStringList MainWindow::data_parsing(QByteArray &input, QList<DATA_PAR_T> list,bool disp_hex)
{
    QString str = input.toHex().toUpper();
    QStringList result_str_list;
    result_str_list.append(str);
    double value = 0;

    int data_type_length = list.length();    //数据类型的个数

    /* 重新计算起始位和偏移 */
    list[0].start = 0;
    for (int var = 1; var < data_type_length; ++var) {
        list[var].start = list[var-1].start + list[var-1].length;
    }

    /* 检查数据长度 */
    if(input.length() < (list[list.length()-1].start+list[list.length()-1].length))
    {
        qDebug()<<input.length();
        qDebug()<<(list[list.length()-1].start+list[list.length()-1].length);
        result_str_list.append("数据长度太短");
        return result_str_list;
    }



    /* 开始解析数据 */
    foreach(DATA_PAR_T data_parsing,list)
    {
        str = data_parsing.desc+":";
        if(data_parsing.data_type == 0)      //字符形式
        {
            str += input_data.mid(data_parsing.start,data_parsing.length);
            str += data_parsing.unit;
        }
        else if(data_parsing.data_type == 1)      //二进制
        {
            uint32_t data = 0;
            uint8_t data_byte = 0;
            uint8_t error = 0;  //记录0XFF的次数  如果整个数据都是0XFF  那么这个数据无效
            //合成数据
            for (int i = 0; i < data_parsing.length; ++i) {
                data <<= 8;
                data_byte = static_cast<uint8_t>(input_data.at(data_parsing.start+i));
                data |= data_byte;
                if(data_byte == 0xff)
                    error++;
            }
            //qDebug()<<data;
            if(error == data_parsing.length)     //说明全部是ff
            {
                str += "无效值";
                if(disp_hex == true)
                {
                    str += " HEX:";
                    str += ("0X" + result_str_list.at(0).mid(data_parsing.start*2,data_parsing.length*2));
                }
            }
            else
            {
                value = data;
                value = (value*data_parsing.precision) + data_parsing.offset;
                //qDebug()<<value;
                str += QString::number(value);
                str += data_parsing.unit;
                if(disp_hex == true)
                {
                    str += " HEX:";
                    str += ("0X" + result_str_list.at(0).mid(data_parsing.start*2,data_parsing.length*2));
                }
            }

        }
        else if(data_parsing.data_type == 2)      //二进制数组
        {
            for (int i = 0; i < data_parsing.length; ++i) {
                str += QString::number(input_data.at(data_parsing.start+i));
                str += " "; //增加空格
            }
            str += data_parsing.unit;
        }

        result_str_list.append(str);
    }
    return result_str_list;
}


/**
  * @brief 根据文件路径获取协议解析结构体
  * @param file_path-文件路径 必须包含到文件名以及后缀
  *        data_psrsing-存储解析后的数据
  * @retval	true-解析成功 flase-解析失败
  */
bool MainWindow::import_protocol(QString file_path,QList<DATA_PAR_T> &data_psrsing)
{

    QFile file(file_path);
    if(!file.open(QIODevice::ReadOnly ))
    {
        //文件打开失败
        return false;
    }

    QByteArray file_data = file.readAll();  //读取文件

    ui->textEdit_json_file->clear();
//    ui->textEdit_json_file->append(file_data);
    ui->lineEdit_file_path->setText(file_path);

    file.close();

    QJsonParseError jsonError;
    QJsonDocument doucment = QJsonDocument::fromJson(file_data, &jsonError);  // 转化为 JSON 文档
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) {  // 解析未发生错误
        if (doucment.isObject()) { // JSON 文档为对象
            QJsonObject object = doucment.object();  // 转化为对象
            if(object.contains("data"))     //查找指定的key
            {
                QJsonValue value = object.value("data");

                if(value.isArray())
                {
                    QJsonArray data_array = value.toArray();

                    foreach(QJsonValue data_value,data_array)
                    {
                        QJsonObject data_object = data_value.toObject();
                        /* 获取数据 */
                        QJsonValue value_desc = data_object.value("desc");
                        QJsonValue value_start = data_object.value("start");
                        QJsonValue value_length = data_object.value("length");
                        QJsonValue value_precision = data_object.value("precision");
                        QJsonValue value_offset = data_object.value("offset");
                        QJsonValue value_unit = data_object.value("unit");
                        QJsonValue value_data_type = data_object.value("data_type");
                        /* 检查数据完整性 */
                        if(value_desc.isNull() || value_start.isNull() || value_length.isNull()||
                           value_precision.isNull() || value_offset.isNull() || value_unit.isNull()||
                           value_data_type.isNull())
                        {
                            return false;
                        }
                        /* 填充数据 */
                        DATA_PAR_T _date_parsing;
                        _date_parsing.desc = value_desc.toString();
                        _date_parsing.unit = value_unit.toString();
                        _date_parsing.start = value_start.toInt();
                        _date_parsing.length = value_length.toInt();
                        _date_parsing.offset = value_offset.toInt();
                        _date_parsing.data_type = value_data_type.toInt();
                        _date_parsing.precision = value_precision.toDouble();
                        data_psrsing.append(_date_parsing);
                    }
                    QString json_str = doucment.toJson();
                    QString json_display = doucment.toJson();
                    bool key_flag = false;
                    bool value_int_flag = false;
                    //<span style=" color:#000000;">KEY</span>
                    for (int var = 0; var < json_display.length(); ++var) {
                        if(json_display.at(var) == '"')     //双引号
                        {
                            if(key_flag == false)
                            {
                                //json_display.insert(var,QString("<span style=\" color:#d3db74;\">"));
                                QString start("<span style=\" color:#d3db74;\">");
                                json_display.insert(var+1,(start));
                                var += start.length()-1;
                                key_flag = true;
                            }
                            else
                            {
                                key_flag = false;
                                QString end("</span>");
                                json_display.insert(var,QString(end));
                                //var += sizeof(end);
                                var += end.length();
                            }
                        }
                        else if(json_display.at(var) == ':')
                        {
                            if(json_display.at(var+1)!='"' && json_display.at(var+2)!='"' && json_display.at(var+2)!='[')
                            {
                                value_int_flag = true;
                                QString start("<span style=\" color:#9e80ff;\">");
                                json_display.insert(var+1,(start));
                                var += start.length()-1;
                            }
                        }
                        else if((json_display.at(var) == ',' || json_display.at(var) == '}')&&value_int_flag==true)
                        {
                            value_int_flag = false;
                            QString end("</span>");
                            json_display.insert(var,QString(end));
                            var += end.length();
                        }
                    }
                    json_display.replace("\n","<br>");
                    json_display.replace("  ","&nbsp;");
                    ui->textEdit_json_file->append(json_display);

                    return true;
                }
                else {
                    return false;
                }
            }
            else {
                return false;
            }

        }
    }
    else {
        return false;
    }
    return false;
}


void MainWindow::on_comboBox_protocol_type_activated(int index)
{
    external_data_psrsing.clear();
    if(import_protocol(protocol_file_path_list.at(index),external_data_psrsing)==false)
    {
        QMessageBox::warning(this,"error","协议文件异常",QMessageBox::Ok);
    }

}

void MainWindow::on_pushButton_remove_clicked()
{
    ui->lineEdit_file_path->clear();
    ui->textEdit_json_file->clear();

    QJsonParseError jsonError;
    QJsonDocument doucment = QJsonDocument::fromJson(application_file_data, &jsonError);  // 转化为 JSON 文档
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError))
    {  // 解析未发生错误
        if (doucment.isObject())
        { // JSON 文档为对象
            QJsonObject object = doucment.object();  // 转化为对象
            if(object.contains("protocol_list"))     //查找指定的key
            {
                QJsonValue value = object.value("protocol_list");

                if(value.isArray())
                {
                    int index = 0;
                    QJsonArray data_array = value.toArray();
                    index = ui->comboBox_protocol_type->currentIndex();
                    if(data_array.count() > index)
                    {
                        try {
                            data_array.removeAt(index);
                        } catch (QString ex) {
                            qDebug()<<ex;
                        }

                    }
                    object.remove("protocol_list");     //删除key
                    object.insert("protocol_list",data_array);
                    doucment.setObject(object);
                    //保存文件
                    application_file_data.clear();
                    application_file_data = doucment.toJson();
                    QFile file("application.json");
                    file.open(QFile::WriteOnly|QFile::Truncate);
                    file.close();
                    if(file.open(QIODevice::ReadWrite|QIODevice::Text))
                    {
                        file.write(application_file_data);
                        file.close();
                    }
                    protocol_file_path_list.clear();
                    init_protocol_list(application_file_data);
                    /* 重新定位combox的位置 */
                    if((ui->comboBox_protocol_type->count()>index)&&
                       (ui->comboBox_protocol_type->count()>0))
                    {//如果删除后的数量比之前删除那个的位置还要大 就定位到下一个
                        ui->comboBox_protocol_type->setCurrentIndex(index);
                        ui->comboBox_protocol_type->activated(index);
                    }
                    else if((ui->comboBox_protocol_type->count()<=index)&&
                            (ui->comboBox_protocol_type->count()>0))
                    {//如果删除后的数量比之前删除那个的位置要小(也就是最后一个被删除了) 就定位到前一个
                        ui->comboBox_protocol_type->setCurrentIndex(index-1);
                        ui->comboBox_protocol_type->activated(index-1);
                    }
                }
            }
        }
    }
}



/**
  * @brief 调用外部js脚本计算CRC
  * @param hex_str-十六进制字符串(不含空格)
  *        func_name-js脚本中的函数名
  * @retval	CRC的十六进制字符串
  */
QString MainWindow::check_crc_from_js(QString hex_str, QString func_name)
{
    if(func_name.isEmpty() || hex_str.isEmpty())
        return nullptr;
    QString result;
    QFile scriptFile("default.js");
    if (!scriptFile.open(QIODevice::ReadOnly))
    {
        result.clear();
        return nullptr;
    }
    QTextStream out(&scriptFile);
    QString contents = out.readAll();
    scriptFile.close();

    QScriptValueList args;      //调用js方法时传入的参数
    QScriptEngine engine;
    QScriptValue js = engine.evaluate(contents);        //个人理解：加载js文本到操作引擎
    QScriptValue func;

    args << QScriptValue(hex_str);
    func = engine.globalObject().property(func_name);   //调用js方法
    result = func.call(QScriptValue(), args).toString();
    quint32 value = func.call(QScriptValue(), args).toUInt32();
    qDebug() << "result:" << result;
    return QString::number(value,16).toUpper();
}
